/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.kylingroup.JavaFX.Task;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.concurrent.Task;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser;
import javafx.stage.Stage;

/**
 *
 * @author kylin
 */
public class JavaFxUnzipWIthProgress extends Application{

    @Override
    public void start(Stage primaryStage) throws Exception {
        HBox sourcepane=new HBox();
        Label lsource=new Label("Source:");
        TextField tsource=new TextField();
        Button btnsource=new Button("select");
        btnsource.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {
                FileChooser filechooser=new FileChooser();
                filechooser.setTitle("Select a source file");
                filechooser.setInitialDirectory(new File(System.getProperty("user.home")));
                File file=filechooser.showOpenDialog(primaryStage);
                if(file!=null){
                    tsource.setText(file.getAbsolutePath());
                }
            }
        });
        sourcepane.getChildren().addAll(lsource,tsource,btnsource);
        
        
        HBox targetpane=new HBox();
        Label ltarget=new Label("Target:");
        TextField ttarget=new TextField();
        Button btntarget=new Button("select");
        btntarget.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {
                DirectoryChooser chooser=new DirectoryChooser();
                chooser.setTitle("Select a extract directory");
                chooser.setInitialDirectory(new File(System.getProperty("user.home")));
                File extractdir=chooser.showDialog(primaryStage);
                if(extractdir.exists()){
                    ttarget.setText(extractdir.getAbsolutePath());
                }
            }
        });
        
        targetpane.getChildren().addAll(ltarget,ttarget,btntarget);

        
        HBox buffersizepane=new HBox();
        Label lbuffersize=new Label("set buffersize:");
        TextField tbuffersize=new TextField();
        buffersizepane.getChildren().addAll(lbuffersize,tbuffersize);
        
        HBox sleeppane=new HBox();
        Label lsleep=new Label("Set thread sleep time:");
        TextField tsleep=new TextField();
        sleeppane.getChildren().addAll(lsleep,tsleep);
        
        ProgressBar bar = new ProgressBar();
        bar.setProgress(0);

        TextArea area=new TextArea();
        Button btnStart = new Button("Start to extract");
        btnStart.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {
                File source=new File(tsource.getText());
                String extractdir=ttarget.getText();

                int buffersize=Integer.parseInt(tbuffersize.getText());
                int sleep=Integer.parseInt(tsleep.getText());

                Extractor task=new Extractor(source,extractdir,buffersize,sleep);
                
                bar.progressProperty().bind(task.progressProperty());

                task.addEventHandler(WorkerStateEvent.WORKER_STATE_SUCCEEDED,
                    new EventHandler<WorkerStateEvent>(){
                    @Override
                    public void handle(WorkerStateEvent event) {
                        HashMap<String,String> info=task.getValue();
                        area.appendText("success\n");
                        area.appendText("source file:"+info.get("sourcefile")+"\n");
                        area.appendText("extract dir:"+info.get("extractdir")+"\n");
                        area.appendText("size:"+info.get("size")+"\n");
                        area.appendText("buffersize:"+info.get("buffersize")+"\n");
                    } 
                });
                new Thread(task).start();
            }
        });
        
        VBox vBox = new VBox();
        vBox.setPadding(new Insets(5, 5, 5, 5));
        vBox.setSpacing(5);
        vBox.getChildren().addAll(sourcepane,targetpane,buffersizepane,sleeppane,bar,btnStart,area);
        
        StackPane root = new StackPane();
        root.getChildren().add(vBox);
 
        Scene scene = new Scene(root, 350, 250);
 
        primaryStage.setTitle("unzip file demo");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    
    public static void main(String[] args) {
        launch(args);
    }
}
class Extractor extends Task<HashMap<String,String>>{
    
    private String extractdir=System.getProperty("user.dir")+"/plugins";
    private File sourcefile=null;
    private int buffersize=0;
    private int sleep=0;
    private HashMap<String,String> info=null;
            
    public Extractor(File sourcefile,String extractdir,int buffersize,int sleep){
        this.sourcefile=sourcefile;
        this.extractdir=extractdir;
        this.buffersize=buffersize;
        this.sleep=sleep;
        info=new HashMap<String,String>();
    }
    
    @Override
    protected HashMap<String, String> call() throws Exception {
        try{
            File extractfolder=new File(extractdir);
            if(!extractfolder.exists()){
                extractfolder.mkdirs();
            }
            
            BufferedOutputStream dest=null;
            BufferedInputStream is=null;
            ZipEntry entry;
            ZipFile zipfile=new ZipFile(sourcefile);

            Enumeration e1=zipfile.entries();
            Enumeration e2=zipfile.entries();
            
            long size=0;
            int rlength=0;
            
            //get uncompressed total size
            while(e1.hasMoreElements()){
                entry=(ZipEntry)e1.nextElement();
                size+=entry.getSize();
            }

            while(e2.hasMoreElements()){
                entry=(ZipEntry)e2.nextElement();
                String subfile=extractdir+File.separator+entry.getName();
                
                if(entry.isDirectory()){
                    makeDir(subfile);
                }else{
                    is=new BufferedInputStream(zipfile.getInputStream(entry));
                    int ins;
                    
                    byte data[] = new byte[buffersize];
                    FileOutputStream fos = new FileOutputStream(subfile);
                    
                    dest = new BufferedOutputStream(fos,buffersize);
                    while((ins=is.read(data,0,data.length))!=-1){
                        dest.write(data,0,ins);
                        rlength+=ins;
                        updateProgress(rlength,size);
                        Thread.sleep(sleep);
                    }
                    dest.flush();
                    dest.close();
                    is.close();
                }
            }
            info.put("sourcefile", sourcefile.getAbsolutePath());
            info.put("extractdir", extractfolder.getAbsolutePath());
            info.put("size", String.valueOf(size));
            info.put("buffersize", String.valueOf(buffersize));

        } catch (Exception e) {
            e.printStackTrace();
        }
        return info;
    }
    
    private boolean makeDir(String unZipDir){
        boolean b=false;
        try{
            File f=new File(unZipDir);
            if(!f.exists()){
                b = f.mkdirs();
            }
        }catch(Exception e) {
            e.printStackTrace();
            return b;
        }
        return b;
    }
}
